The fundamental task of every processor is to execute programs. How a processor handles this task, and how the programs must present themselves to the processor for execution, are governed by an instruction set architecture (“ISA”) and the microarchitecture of the processor. An ISA is analogous to a programming model and relates principally to how instructions in a program should be formatted in order to be properly decoded and executed by the processor, although an ISA may also specify other aspects of the processor, such as native data types, registers, addressing modes, memory architecture, interrupt and exception handling, and external I/O. The microarchitecture principally governs lower level details regarding how instructions are decoded and executed, including the constituent parts of the processor (e.g., the execution units, such as fixed and floating point execution units) and how these interconnect and interoperate to implement the processor's architectural specification.
An ISA typically includes a specification of the format of each type of instruction that is capable of being executed by a particular processor design. Typically, an instruction will be encoded to include an operational code (“opcode”) that identifies the type of instruction, as well as one or more operands that identify input and/or output data to be processed by the instruction. In many processor designs, such as Reduced Instruction Set Computer (“RISC”) designs and other load-store designs, data is principally manipulated within a set of general purpose registers (GPR's) (often referred to as a register file), with load and store instructions used to respectively retrieve input data into a GPR from memory and store result or output data from the GPR back to memory. Thus, for a majority of the instructions that manipulate data, the instructions specify one or more input or source registers from which input data is retrieved (such as through the use of source addresses specifying target locations of the register files from which to retrieve data), and an output or destination register, which may be the same as one or more of the input or source registers, to which data is written (such as through the use of a target address specifying a target location of the register file from which to write data).
Instructions are typically defined in an ISA to be a fixed size, such as 32 bits or 64 bits wide. While multiple 32 or 64 bit values may be used to specify an instruction, the use of multiple values is undesirable because the multiple values take more time to propagate through the processor and significantly increase design complexity. With these fixed instruction widths, only a limited number of bits are available for use as opcodes and operands.
Each unique instruction type conventionally requires a unique opcode, so in order to support a greater number of instruction types (a continuing need in the industry), additional bits often must be allocated to the opcode portion of an instruction architecture. In some instances, opcodes may be broken into primary and secondary opcodes, with the primary opcode defining an instruction type and the secondary opcode defining a subtype for a particular instruction type. However, even when primary and secondary opcodes are used, both occupy bit positions within the instruction.
Likewise, a continuing need exists for expanding the number of registers supported by an ISA, since improvements in fabrication technology continue to enable greater numbers of registers to be architected into an integrated circuit, and in general performance improves as the number of registers increases. Each register requires a unique identifier as well, so as the number of registers increases, the number of bit positions in each instruction required to identify all supported registers likewise increases.
As an example, consider a processor architecture that supports 32-bit instructions with 6-bit primary opcode fields, and thus that supports a total of 64 types, or classes, or instructions. If, for example, it is desirable to implement within this architecture a class of instructions that identifies up to three source registers (also referred to as source addresses) and a separate destination register (also referred to as a target address) from a register file of 64 registers, or addresses, each address requires a 6-bit field. As such, 6 bits are needed for the primary opcode, 18 bits are needed for the source addresses, and 6 bits are needed for the target address, leaving only two bits for an extended opcode. This allows for only four possible instructions in this instruction class. However, in the event that the register file has 128 registers, or entries, each address requires a 7-bit field. As such, the primary opcode must be reduced to 4 bits, 21 bits are needed for the source addresses, 7 bits are needed for the target address, and no bits are available for an extended opcode. This results in a drastically reduced number of opcodes available for use to perform operations.
In most instances, however, more instructions types are needed for an architecture to be useful. For example, an instruction class for performing floating point operations may need instruction types that perform addition, subtraction, multiplication, fused multiply-add operations, division, exponentiation, trigonometric operations, comparison operations, and others.
Conventional attempts have been made to address these limitations. For example, three-source operations may be made destructive, meaning that the target and one source address would be implicitly equal, such that one address field in the above example would not be needed, freeing up space for additional extended opcodes. Destructive operations, however, are not convenient for compilers and software engineers, because often an extra copy of the source data that would be overwritten by the destructive operation needs to be saved away in a temporary register, which can have performance problems in addition to using valuable temporary register space.
Therefore, a significant need continues to exist in the art for a manner of increasing the number and complexity of instructions supported by an instruction set architecture.